home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 11 / Cream of the Crop 11-2.iso / extra_2 / flmgmtcl.zip / DIR.CPP next >
C/C++ Source or Header  |  1995-11-02  |  25KB  |  878 lines

  1. // ==========================================================================
  2. //                             Class Implementation : CDirSpec
  3. // ==========================================================================
  4.  
  5. // Source file : dir.cpp
  6.  
  7. // Source : Periphere NV (R.Mortelmans)
  8. // Creation Date :        2nd November. 1995
  9. // Last Modification : 2nd November. 1995
  10.                           
  11. // //////////////////////////////////////////////////////////////////////////
  12.  
  13. #include "stdafx.h"        // standard MFC include
  14. #include "dir.h"        // class specification
  15. #include "path.h"        // For MakeUnique() and FindLowerDirectory()
  16.  
  17. #include <direct.h>        // For directory functions (getdcwd(), ...)
  18. #include <stdlib.h>        // For constant definitions  (_MAX_DIR, ...)
  19. #include <dos.h>        // For _find_t, _dos_findfirst, ...
  20.  
  21. #define _A_ALL   _A_ARCH | _A_HIDDEN | _A_NORMAL | _A_RDONLY | _A_SYSTEM
  22.  
  23. #ifdef _DEBUG
  24. #undef THIS_FILE
  25. static char BASED_CODE THIS_FILE[] = __FILE__;
  26. #endif                                  
  27.  
  28. #include "filelmt.h"    // for invalid chars
  29.  
  30. IMPLEMENT_DYNAMIC(CDirSpec, CObject)
  31.  
  32. #define new DEBUG_NEW
  33.  
  34. /////////////////////////////////////////////////////////////////////////////
  35. // Definition of static members
  36.  
  37.  
  38. // Data members -------------------------------------------------------------
  39. // protected:
  40.  
  41. // private:
  42.     // CString m_sDrive;
  43.     // --- The drive specification consists of a drive letter (capital letter)
  44.     //       followed be a colon
  45.  
  46.     //CString m_sSubdirectory;
  47.     // --- A subdirecory consists of the directory specification, without the drive
  48.     //     and file specification
  49.     //     In case of the root directory, it ends in a back slash, 
  50.     //       otherwise it never ends in a back slash
  51.     
  52. // Member functions ---------------------------------------------------------
  53. // public:
  54.  
  55. CDirSpec::CDirSpec()
  56.     :
  57.     m_sDrive(TEXT("")),
  58.     m_sSubdirectory(TEXT(""))
  59.     {
  60.     }
  61.     
  62. CDirSpec::CDirSpec(const char* pszDirectory)
  63.     {
  64.     // ... Must be valid pointer
  65.     ASSERT(pszDirectory != NULL);
  66.     if (!SetDirectory(pszDirectory))
  67.         {
  68.         TRACE(TEXT("CDirSpec::CDirSpec : An invalid directory (%s) was specified, clearing object\n"),
  69.             pszDirectory);
  70.         Empty();
  71.         }
  72.     }
  73.     
  74. CDirSpec::CDirSpec(const CDirSpec& dirSrc)
  75.     :
  76.     m_sDrive(dirSrc.m_sDrive),
  77.     m_sSubdirectory(dirSrc.m_sSubdirectory)
  78.     {
  79.     }
  80.     
  81. BOOL CDirSpec::AppendDirectory(const CDirSpec dirSecond)
  82.     {
  83.     // The drive spec of dirSecond must be empty or the same as
  84.     // that of *this
  85.     if (!dirSecond.GetDrive().IsEmpty() && (GetDrive() != dirSecond.GetDrive()))
  86.         {
  87.         TRACE(TEXT("CDirSpec::AppendDirectory : Illegal drive spec (%s != %s)\n"),
  88.             (const char*)GetDrive(), (const char*)dirSecond.GetDrive());
  89.         return FALSE;
  90.         }
  91.         
  92.     if (dirSecond.GetSubdirectory().IsEmpty())
  93.         return TRUE;
  94.         
  95.     if (dirSecond.GetSubdirectory().Left(1) == TEXT("\\"))
  96.         {
  97.         TRACE(TEXT("CDirSpec::AppendDirectory : Second dir cannot start with back slash (%s)\n"),
  98.             dirSecond.GetSubdirectory());
  99.         return FALSE;
  100.         }
  101.         
  102.     CString sSubdir = GetSubdirectory();
  103.     if (!sSubdir.IsEmpty() && (sSubdir.Right(1) != TEXT("\\")))
  104.         sSubdir += TEXT("\\");
  105.     return SetSubdirectory(sSubdir += dirSecond.GetSubdirectory());
  106.     }
  107.     
  108. const CDirSpec& CDirSpec::operator=(const CDirSpec& dirSrc)
  109.     {
  110.     m_sDrive =             dirSrc.m_sDrive;
  111.     m_sSubdirectory =     dirSrc.m_sSubdirectory;
  112.     return *this;
  113.     }
  114.     
  115. CString CDirSpec::GetDrive() const
  116.     {
  117.     return m_sDrive;
  118.     }
  119.     
  120. BOOL CDirSpec::SetDrive(const char* pszDrive)
  121.     {
  122.     // ... Must be valid pointer
  123.     ASSERT(pszDrive != NULL);
  124.     if (strlen(pszDrive) == 0)
  125.         {
  126.         m_sDrive = pszDrive;
  127.         return TRUE;
  128.         }
  129.     ASSERT(strlen(pszDrive) != 0);
  130.     if ( (('a' <= pszDrive[0]) && (pszDrive[0] <= 'z')) ||
  131.          (('A' <= pszDrive[0]) && (pszDrive[0] <= 'Z')) 
  132.        )
  133.            {
  134.         m_sDrive = CString(toupper(pszDrive[0])) + ':';
  135.         return TRUE;
  136.         }
  137.     else
  138.         {
  139.         TRACE(TEXT("CDirSpec::SetDrive : Invalid drive specification (%c)\n"), pszDrive[0]);
  140.         return FALSE;
  141.         }
  142.     }
  143.     
  144. void CDirSpec::ForceSetDrive(const char* pszDrive)
  145.     {
  146.     // ... Must be valid pointer
  147.     ASSERT(pszDrive != NULL);
  148.     if ((0 < strlen(pszDrive)) &&
  149.          ( (('a' <= pszDrive[0]) && (pszDrive[0] <= 'z')) ||
  150.            (('A' <= pszDrive[0]) && (pszDrive[0] <= 'Z')) 
  151.          )
  152.        ) 
  153.          VERIFY(SetDrive(CString(toupper(pszDrive[0])) + TEXT(":")));
  154.     else
  155.          VERIFY(SetDrive(TEXT("")));
  156.     }
  157.     
  158. CString CDirSpec::GetSubdirectory() const
  159.     {
  160.     return m_sSubdirectory;
  161.     }
  162.     
  163. BOOL CDirSpec::SetSubdirectory(const char* pszSubdirectory)
  164.     {
  165.     // ... Must be valid pointer
  166.     ASSERT(pszSubdirectory != NULL);
  167.     CString sSubdirectory(pszSubdirectory);
  168.     // ... Short circuit evaluation
  169.     if ( (sSubdirectory.Right(1) != TEXT("\\")) || (sSubdirectory.GetLength() == 1))
  170.         {
  171.         sSubdirectory.MakeUpper();
  172.         if ((int)strcspn(sSubdirectory, INVALID_DIR_CHARS) != sSubdirectory.GetLength())
  173.             {
  174.             TRACE(TEXT("CFileSpec::SetSubdirectory : Subdirectorye (%s) contains illegal characters\n"), sSubdirectory);
  175.             return FALSE;
  176.             }
  177.         m_sSubdirectory = sSubdirectory;
  178.         return TRUE;
  179.         }
  180.     else
  181.         {
  182.         TRACE(TEXT("CDirSpec::SetSubdirectory : Only root directory may end in \"\\\", not %s\n"), sSubdirectory);
  183.         return FALSE;
  184.         }
  185.     }
  186.  
  187. void CDirSpec::ForceSetSubdirectory(const char* pszSubdirectory)
  188.     {
  189.     // ... Must be valid pointer
  190.     ASSERT(pszSubdirectory != NULL);
  191.     CString sSubdirectory(pszSubdirectory);
  192.     int nIndexWrongChar;
  193.     while ((nIndexWrongChar = (int)strcspn(sSubdirectory, INVALID_DIR_CHARS)) != sSubdirectory.GetLength())
  194.         {
  195.         sSubdirectory = sSubdirectory.Left(nIndexWrongChar) + sSubdirectory.Mid(nIndexWrongChar + 1);
  196.         }
  197.     if ( (sSubdirectory.Right(1) == TEXT("\\")) && (sSubdirectory.GetLength() != 1))
  198.         // Remove trailing back slash
  199.         sSubdirectory = sSubdirectory.Mid(0,sSubdirectory.GetLength() - 1);
  200.     VERIFY(SetSubdirectory(sSubdirectory));
  201.     }
  202.     
  203. CDirSpec CDirSpec::GetLastSubdirectory() const
  204.     {
  205.     CDirSpec resultDir;
  206.     CString sSubdir;
  207.     int nIndex;
  208.     
  209.     resultDir.SetDrive(GetDrive());
  210.     sSubdir = GetSubdirectory();
  211.     nIndex = sSubdir.ReverseFind('\\');
  212.     if (nIndex == -1)
  213.         // No back slash found
  214.         resultDir.SetSubdirectory(GetSubdirectory());
  215.     else
  216.         {
  217.         ASSERT(0 <= nIndex);
  218.         resultDir.SetSubdirectory(sSubdir.Mid(nIndex + 1));
  219.         }
  220.     return resultDir;
  221.     }
  222.     
  223. void CDirSpec::RemoveLastSubdirectory()
  224.     {
  225.     int nIndex;
  226.  
  227.     nIndex = m_sSubdirectory.ReverseFind('\\');
  228.     if (nIndex != -1)
  229.         // Back slash found
  230.         {
  231.         ASSERT(0 <= nIndex);
  232.         if (nIndex != 0)
  233.             // Not the root directory
  234.             m_sSubdirectory = m_sSubdirectory.Left(nIndex);
  235.         else
  236.             // The root directory
  237.             m_sSubdirectory = TEXT("\\");
  238.         }
  239.     }
  240.     
  241. CString CDirSpec::GetDirectory() const
  242.     {
  243.     return m_sDrive + m_sSubdirectory;
  244.     }
  245.     
  246. BOOL CDirSpec::SetDirectory(const char* pszDirectory)
  247.     {
  248.     // ... Must be valid pointer
  249.     ASSERT(pszDirectory != NULL);
  250.     CString sDirectory(pszDirectory);
  251.     if (sDirectory.Mid(1,1) == TEXT(":"))
  252.         {
  253.         if (!SetDrive(sDirectory.Left(2)))
  254.             return FALSE;
  255.         if (3 <= sDirectory.GetLength())
  256.             return SetSubdirectory(sDirectory.Mid(2));
  257.         else
  258.             return SetSubdirectory(TEXT(""));
  259.         }
  260.     else
  261.         {
  262.         return SetDrive(TEXT("")) && SetSubdirectory(sDirectory);
  263.         }
  264.     }
  265.     
  266. void CDirSpec::ForceSetDirectory(const char* pszDirectory)
  267.     {
  268.     // ... Must be valid pointer
  269.     ASSERT(pszDirectory != NULL);
  270.     if ((0 < strlen(pszDirectory)) && (pszDirectory[1] == ':'))
  271.         {
  272.         ForceSetDrive(&pszDirectory[0]);
  273.         if (3 <= strlen(pszDirectory))
  274.             ForceSetSubdirectory(&pszDirectory[2]);
  275.         else
  276.             ForceSetSubdirectory(TEXT(""));
  277.         }
  278.     else
  279.         {
  280.         ForceSetDrive(TEXT(""));
  281.         ForceSetSubdirectory(pszDirectory);
  282.         }
  283.     }
  284.     
  285. CString CDirSpec::GetFileSystemType()
  286.     {
  287.     if (m_sDrive.IsEmpty())
  288.         {
  289.         TRACE(TEXT("CDirSpec::GetFileSystemType : No drive specified, returning empty string\n"));
  290.         return TEXT("");
  291.         }
  292. #ifdef WIN32
  293.     const int nMaxSystemNameLength = 50;
  294.     char szSystemName[nMaxSystemNameLength + 1];
  295.     BOOL bSuccess;
  296.     // ... The Error Mode is temporarily set to SEM_FAILCRITICALERRORS to 
  297.     //       allow failures to immediately return to the calling program.  
  298.     //     This eliminates unwanted dialog boxes that prompt for disks 
  299.     //     to be placed in the drive.
  300.     UINT nOldErrorMode = ::SetErrorMode(SEM_FAILCRITICALERRORS); 
  301.       bSuccess = GetVolumeInformation(m_sDrive + TEXT("\\"), NULL, 0, NULL,
  302.            NULL, NULL, szSystemName, nMaxSystemNameLength);
  303.     // ... Restore the error code
  304.     ::SetErrorMode(nOldErrorMode);
  305.     if (bSuccess)
  306.         return szSystemName;
  307.     else
  308.         {
  309.         TRACE(TEXT("CDirSpec::GetFileSystemType : Could not determine file system, returning empty string\n"));
  310.         return TEXT("");
  311.         }
  312. #else
  313.     // WIN16 cannot distinguish between file systems, so always return "FAT"
  314.     return TEXT("FAT");
  315. #endif
  316.     }
  317.  
  318. BOOL CDirSpec::MakeTemp()
  319.     {
  320. #ifdef WIN32
  321.     CString sTempPath;
  322.     BOOL bSuccess = ::GetTempPath(_MAX_PATH, sTempPath.GetBuffer(_MAX_PATH));
  323.     sTempPath.ReleaseBuffer();
  324.     if (bSuccess)
  325.         {
  326.         // we'll have to use FORCE... because the path returned
  327.         // by WIN32 api ends with a '\'
  328.         ForceSetDirectory(sTempPath);
  329.         return TRUE;
  330.         }
  331.     else
  332.         return FALSE;
  333. #else
  334.     char path_buffer[_MAX_PATH + 1]; 
  335.     char chDriveLetter = 'C';
  336.     char* pszSlash = NULL;
  337.  
  338.     // Get temp path
  339.     ::GetTempFileName(0,             // Use the default drive
  340.                       TEXT("TMP"),         // TMP-prefix
  341.                       1,             // Do not try to open and close the file
  342.                       path_buffer);    // Result
  343.     // ... Remove the file name (keep only the dir, WITHOUT trailing black slash!)
  344.     pszSlash = strrchr(path_buffer, '\\');
  345.     if (pszSlash != NULL)
  346.         *pszSlash = '\0';
  347.         
  348.     if (*path_buffer != '\0')
  349.         {
  350.         return SetDirectory(path_buffer);
  351.         }
  352.     else
  353.         {
  354.         TRACE(TEXT("CDirSpec::MakeTemp : Could not make temp path, using root of temp drive\n"));
  355.         VERIFY(SetDirectory(TEXT("\\")));
  356.         return SetDrive(CString(::GetTempDrive(chDriveLetter)));
  357.         }
  358. #endif
  359.     }
  360.  
  361. BOOL CDirSpec::MakeUnique()
  362.     {
  363.     CPathSpec path;
  364.     // First convert to file name and at the end convert back to dir
  365.     path.SetPath(GetDirectory());
  366.     if (path.MakeUnique() && SetDirectory(path.GetPath()))    // Short circuit evaluation
  367.         return TRUE;
  368.     else
  369.         {
  370.         TRACE(TEXT("CDirSpec::MakeUnique : Could not make unique dir\n"));
  371.         return FALSE;
  372.         }
  373.     }
  374.     
  375. BOOL CDirSpec::MakeLargestExisting()
  376.     {
  377.     // Create a temp path spec to make the dir spec absolute
  378.     CPathSpec absolutePath;
  379.     // .... Dir spec should already be avlid and file spec is valid too,
  380.     //      so path spec should be valid as well !
  381.     VERIFY(absolutePath.SetPath(*this, CFileSpec(TEXT("dummy.tmp"))));
  382.     if (!absolutePath.MakeAbsolute())
  383.         {
  384.         TRACE(TEXT("CDirSpec::MakeLargestExisting : Could not make '%s' absolute, failing\n"),
  385.             (const char*)absolutePath.GetPath());
  386.         // ... Use root directory (best we can do)
  387.         VERIFY(SetDrive(absolutePath.GetDrive()));
  388.         VERIFY(SetSubdirectory(TEXT("\\")));
  389.         return FALSE;
  390.         }
  391.  
  392.     // ... Use direcory part of absoluite path
  393.     operator=(absolutePath);
  394.  
  395.     // First check whether the dir spec exists entirely
  396.     if (Exists())
  397.         return TRUE;
  398.  
  399.     // Now iterate all the subdirectories of this absolute dir spec
  400.     // starting from the root, until all subdirs are tried or a non-existing 
  401.     // subdirectory has been encountered
  402.     // E.g. if dir spec = C:\ONE\TWO\THREE then
  403.     //        then try C:\  
  404.     //        then try C:\ONE
  405.     //        then try C:\ONE\TWO
  406.     // If one of them does not exist, the search is stopped
  407.     const char* pszSubdirBegin;
  408.     const char* pszPrevSubdirEnd;
  409.     const char* pszSubdirEnd;
  410.     BOOL bExist = TRUE;
  411.     CDirSpec testDir;
  412.  
  413.     pszSubdirBegin = m_sSubdirectory;
  414.     pszPrevSubdirEnd = pszSubdirBegin;
  415.     pszSubdirEnd = strchr(pszSubdirBegin, '\\');
  416.     while (bExist && (pszSubdirEnd != NULL))
  417.         {
  418.         // ... End the subdir spec BEFORE the terminating back slash
  419.         //     except when the root (first char is back slash)
  420.         if (pszSubdirBegin == pszSubdirEnd)
  421.             pszSubdirEnd++;
  422.         VERIFY(testDir.SetDrive(GetDrive()));
  423.         VERIFY(testDir.SetSubdirectory(CString(pszSubdirBegin, pszSubdirEnd - pszSubdirBegin)));
  424.         bExist = testDir.Exists();
  425.         if (bExist)
  426.             {
  427.             // Get next subdir
  428.             pszPrevSubdirEnd = pszSubdirEnd;
  429.             pszSubdirEnd = strchr(pszSubdirEnd + 1, '\\');
  430.             }
  431.         }
  432.  
  433.     if (bExist)
  434.         {
  435.         // All the checked subdirectories exist, 
  436.         // and we know that the complete dir spec does not exist
  437.         ASSERT(!Exists());
  438.         ASSERT(pszSubdirEnd == NULL);
  439.         ASSERT(pszPrevSubdirEnd != NULL);
  440.         VERIFY(SetSubdirectory(CString(pszSubdirBegin, pszPrevSubdirEnd - pszSubdirBegin)));
  441.         }
  442.     else
  443.         {
  444.         // A non-existing subdir has been encountered, 
  445.         // use the last existing sub dir
  446.         ASSERT(pszPrevSubdirEnd != NULL);
  447.         VERIFY(SetSubdirectory(CString(pszSubdirBegin, pszPrevSubdirEnd - pszSubdirBegin)));
  448.         }
  449.  
  450.     // The dir spec must exist now
  451.     ASSERT(Exists());
  452.     return TRUE;
  453.     }
  454.  
  455. BOOL CDirSpec::Exists() const
  456.     {
  457.     // Assume that an empty directory or the root directory always exist
  458.     // (although CFile::GetStatus("C:\\") return FALSE)
  459.     if (GetSubdirectory().IsEmpty() || (GetSubdirectory() == TEXT("\\")))
  460.         return TRUE;
  461.  
  462.     CFileStatus fileStatus;
  463.     return ( (CFile::GetStatus(GetDirectory(), fileStatus)) && 
  464.              (fileStatus.m_attribute & CFile::directory) );
  465.     }
  466.     
  467. BOOL CDirSpec::IsEmpty() const
  468.     {
  469.     return GetDirectory().IsEmpty();
  470.     }
  471.     
  472. void CDirSpec::Empty()
  473.     {
  474.     m_sDrive.Empty();
  475.     m_sSubdirectory.Empty();
  476.     }
  477.     
  478. BOOL CDirSpec::IsEmptyDir() const
  479.     {
  480.     CPathSpec filePath;
  481.  
  482.     BOOL bFileFound(FALSE);    
  483.     BOOL bValid(FALSE);    
  484.     VERIFY(filePath.SetPath(*this, CFileSpec(TEXT("*.*"))));
  485.  
  486. #ifdef WIN32
  487.     WIN32_FIND_DATA fileData;
  488.  
  489.     HANDLE hFindFile = FindFirstFile(filePath.GetPath(), &fileData);
  490.     if (hFindFile != INVALID_HANDLE_VALUE)
  491.         bFileFound = TRUE;    
  492.     // As long a something is found, but is not a good one, keep searching
  493.     // ... Ignore non-subdirectories and subdirectories starting with a full steop
  494.     while (!bValid && bFileFound)
  495.         {
  496.         if (fileData.cFileName[0] != __TEXT('.'))
  497.             bValid = TRUE;
  498.  
  499.         if (!bValid)    
  500.             bFileFound = FindNextFile(hFindFile, &fileData);
  501.         }
  502.  
  503.     if (hFindFile != INVALID_HANDLE_VALUE)
  504.         FindClose(hFindFile);
  505.  
  506. #else     
  507.     _find_t fileInfo;
  508.  
  509.     bFileFound = !_dos_findfirst(filePath.GetPath(), _A_SUBDIR | _A_ALL, &fileInfo);
  510.  
  511.        while (!bValid && bFileFound)
  512.         {
  513.         if ((strcmp(fileInfo.name, TEXT(".")) != 0) && (strcmp(fileInfo.name, TEXT("..")) != 0))
  514.             bValid = TRUE;
  515.         
  516.         if (!bValid)    
  517.             bFileFound = (_dos_findnext(&fileInfo) == 0);
  518.         }        
  519.  
  520. #endif
  521.  
  522.     return !bValid;
  523.     }
  524.  
  525.     
  526. BOOL CDirSpec::DoGetCurrentDir()
  527.     {
  528.     char pszSubdirectory[_MAX_DIR];
  529.     if(_getcwd(pszSubdirectory, _MAX_DIR) != NULL)
  530.         {
  531.         ASSERT(CString(pszSubdirectory).GetLength() >= 2);
  532.         SetDrive(CString(pszSubdirectory).Left(2));
  533.         SetSubdirectory(CString(pszSubdirectory).Mid(2));
  534.         return TRUE;
  535.         }
  536.     else
  537.         {
  538.         TRACE(TEXT("CDirSpec::DoGetCurrentDir : Error occurred while accessing current directory\n"));
  539.         return FALSE;
  540.         }
  541.     }
  542.  
  543. BOOL CDirSpec::DoSetCurrentDir() const
  544.     {
  545.     if (!m_sDrive.IsEmpty())
  546.         if (_chdrive((int)m_sDrive[0] - 'A' + 1) != 0)
  547.             {
  548.             TRACE(TEXT("CDirSpec::DoSetCurrentDir : Drive change to %s failed\n"), m_sDrive);
  549.             return FALSE;
  550.             }
  551.     if (!m_sSubdirectory.IsEmpty())
  552.         if (_chdir(m_sSubdirectory) != 0)
  553.             {
  554.             TRACE(TEXT("CDirSpec::DoSetCurrentDir : Directory change to %s failed\n"), m_sSubdirectory);
  555.             return FALSE;
  556.             }
  557.     return TRUE;
  558.     }
  559.     
  560. BOOL CDirSpec::DoMakeNew() const
  561.     {
  562.     // Do not try to create a directory with an empty name and
  563.     // do not try to create the root directory (it already exists)
  564.     if (!m_sSubdirectory.IsEmpty() && (m_sSubdirectory != TEXT("\\")))
  565.         {
  566.         CString sDir = m_sDrive + m_sSubdirectory;
  567.         // First try to create all the directories in front of the last back slash
  568.         // This is done without error checking, because they may already exist
  569.         int nSlashPosition;
  570.         int nDeltaSlashPosition;             
  571.         
  572.         nDeltaSlashPosition = sDir.Find('\\');
  573.         nSlashPosition = nDeltaSlashPosition;
  574.         while ( nDeltaSlashPosition != -1)
  575.             {
  576.             _mkdir(sDir.Left(nSlashPosition));
  577.             // ... Only root dir can end in \\ and this case is excluded here by spanning is
  578.             ASSERT(sDir.Right(1) != TEXT("\\"));    
  579.             nDeltaSlashPosition = sDir.Mid(nSlashPosition + 1).Find('\\');
  580.             nSlashPosition += nDeltaSlashPosition + 1;
  581.             }
  582.             
  583.         // Now try to create the entire directory specification,
  584.         // with error checking
  585.         if (_mkdir(sDir) != 0)
  586.             {
  587.             TRACE(TEXT("CDirSpec::DoMakeNew : Directory creation %s failed\n"), sDir);
  588.             return FALSE;
  589.             }
  590.         }
  591.     return TRUE;
  592.     }
  593.     
  594. BOOL CDirSpec::DoRemove(BOOL bRecursively /* = FALSE */,
  595.                         BOOL bAlsoRemoveReadOnly /* = FALSE */) const
  596.     {
  597. #ifdef _DEBUG
  598.     if (GetSubdirectory() == TEXT("\\"))
  599.         {
  600.         TRACE(TEXT("CDirSpec::DoRemove : Trying to remove root directory (%s) and all it's subdirectories\n"),
  601.             GetSubdirectory());
  602.         // Dangerous situation : Give user change to abort or go on (retry)
  603.         ASSERT(FALSE);
  604.         }
  605. #endif    
  606.     if (!m_sSubdirectory.IsEmpty())
  607.         {
  608.         if (bRecursively)
  609.             // First remove all underlying directories
  610.             {
  611.             CDirSpec lowerDir;
  612.             lowerDir = FindLowerDirectory();
  613.             while (!lowerDir.IsEmpty())
  614.                 {
  615.                 if (!lowerDir.DoRemove(bRecursively, bAlsoRemoveReadOnly))
  616.                     // Could not remove lower directory, abort
  617.                     return FALSE;
  618.                 lowerDir = FindLowerDirectory();
  619.                 }
  620.             }
  621.             
  622.         // Remove all the files in the directory
  623.         if (!RemoveAllFiles(bAlsoRemoveReadOnly))
  624.             {
  625.             TRACE(TEXT("CDirSpec::DoRemove : Removal of files failed, cannot remove directory %s\n"), GetDirectory());
  626.             return FALSE;
  627.             }
  628.         
  629.         // Remove the directory itself
  630. #ifdef WIN32
  631.         if (!RemoveDirectory(GetDirectory()))
  632. #else
  633.         if (_rmdir(GetDirectory()) != 0)
  634. #endif
  635.             {
  636.             TRACE(TEXT("CDirSpec::DoRemove : Cannot remove directory : %s\n"), GetDirectory());
  637.             return FALSE;
  638.             }
  639.         }
  640.     return TRUE;
  641.     }
  642.  
  643. BOOL CDirSpec::operator==(CDirSpec dirSpec) const
  644.     {
  645.     return ( (m_sDrive == dirSpec.m_sDrive) &&
  646.              (m_sSubdirectory == dirSpec.m_sSubdirectory) );
  647.     }
  648.     
  649. BOOL CDirSpec::operator!=(CDirSpec dirSpec) const
  650.     {
  651.     return ( (m_sDrive != dirSpec.m_sDrive) ||
  652.              (m_sSubdirectory != dirSpec.m_sSubdirectory) );
  653.     }
  654.     
  655. BOOL CDirSpec::operator<=(CDirSpec dirSpec) const
  656.     {
  657.     return (m_sDrive + m_sSubdirectory <= dirSpec.m_sDrive + dirSpec.m_sSubdirectory);
  658.     }
  659.     
  660. BOOL CDirSpec::operator<(CDirSpec dirSpec) const
  661.     {
  662.     return (m_sDrive + m_sSubdirectory < dirSpec.m_sDrive + dirSpec.m_sSubdirectory);
  663.     }  
  664.     
  665. BOOL CDirSpec::operator>=(CDirSpec dirSpec) const
  666.     {
  667.     return (m_sDrive + m_sSubdirectory >= dirSpec.m_sDrive + dirSpec.m_sSubdirectory);
  668.     }
  669.     
  670. BOOL CDirSpec::operator>(CDirSpec dirSpec) const
  671.     {
  672.     return (m_sDrive + m_sSubdirectory > dirSpec.m_sDrive + dirSpec.m_sSubdirectory);
  673.     }
  674.  
  675. #ifdef _DEBUG
  676. void CDirSpec::Dump(CDumpContext& dc) const
  677.     {
  678.     CObject::Dump(dc);
  679.     dc << TEXT("\nm_sDrive : ") << m_sDrive;
  680.     dc << TEXT("\nm_sSubdirectory : ") << m_sSubdirectory;
  681.     }
  682.  
  683. void CDirSpec::AssertValid() const
  684.     {
  685.     CObject::AssertValid();
  686.     }
  687. #endif
  688.  
  689. CDirSpec::~CDirSpec()
  690.     {
  691.     }
  692.  
  693. #ifdef WIN32
  694. BOOL CDirSpec::IsChildDir(LPWIN32_FIND_DATA lpFindFileData)    const
  695.     // --- In  : 
  696.     // --- Out : 
  697.     // --- Returns : if lpFindFileData contains a subdir...
  698.     // --- Effect : 
  699.  
  700. {
  701.     return (
  702.         (lpFindFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  703.         (lpFindFileData->cFileName[0] != __TEXT('.')));
  704. }    
  705. #endif
  706.  
  707. // protected:
  708. CDirSpec CDirSpec::FindLowerDirectory() const
  709.     // --- In  : 
  710.     // --- Out : 
  711.     // --- Returns : A directory that is a subdirectory of this dir spec
  712.     // --- Effect : 
  713.     {
  714.     CDirSpec lowerDir;
  715.     CPathSpec searchPath;
  716.     VERIFY(searchPath.SetPath(*this, CFileSpec(TEXT("*.*"))));
  717.  
  718.     BOOL bDirFound(FALSE);
  719.     BOOL bFileFound(TRUE);
  720.  
  721. #ifdef WIN32
  722.     WIN32_FIND_DATA fileData;
  723.  
  724.     HANDLE hFindFile = FindFirstFile(searchPath.GetPath(), &fileData);
  725.     if (hFindFile != INVALID_HANDLE_VALUE)
  726.         bFileFound = TRUE;    
  727.  
  728.     // As long a something is found, but is not a good one, keep searching
  729.     // ... Ignore non-subdirectories and subdirectories starting with a full steop
  730.     while (!bDirFound && bFileFound)
  731.         {
  732.         bDirFound = IsChildDir(&fileData);
  733.         
  734.         if (!bDirFound)    
  735.             bFileFound = FindNextFile(hFindFile, &fileData);
  736.  
  737.         }
  738.  
  739.     if (hFindFile != INVALID_HANDLE_VALUE)
  740.         FindClose(hFindFile);
  741.  
  742.     if (bDirFound)
  743.         {
  744.         lowerDir = *this;
  745.         VERIFY(lowerDir.AppendDirectory(CDirSpec(fileData.cFileName)));
  746.         return(lowerDir);
  747.         }
  748.     else
  749.         // Returning an empty directory
  750.         return(lowerDir);
  751. #else
  752.     _find_t fileInfo;
  753.     
  754.     bDirFound = !_dos_findfirst(searchPath.GetPath(), _A_SUBDIR | _A_ALL, &fileInfo);
  755.     // As long a something is found, but is not a good one, keep searching
  756.     // ... Ignore non-subdirectories and subdirectories starting with a full steop
  757.     while( (bDirFound) && 
  758.            ( !(fileInfo.attrib & _A_SUBDIR) || (*fileInfo.name == '.') ) )
  759.         bDirFound = !_dos_findnext(&fileInfo);
  760.  
  761.     if (bDirFound)
  762.         {
  763.         lowerDir = *this;
  764.         VERIFY(lowerDir.AppendDirectory(CDirSpec(fileInfo.name)));
  765.         return(lowerDir);
  766.         }
  767.     else
  768.         // Returning an empty directory
  769.         return(lowerDir);
  770. #endif
  771.     }
  772.  
  773. BOOL CDirSpec::RemoveAllFiles(BOOL bAlsoRemoveReadOnly /* = FALSE */) const
  774.     // --- In  : bAlsoRemoveReadOnly : Whether to remove all the files,
  775.     //                even when they are read only (TRUE) or not (FALSE)
  776.     // --- Out : 
  777.     // --- Returns : Whether all the removals succeeded
  778.     // --- Effect : Removes all the files of this directory
  779.     {
  780.     CPathSpec filePath;
  781.     VERIFY(filePath.SetPath(*this, CFileSpec(TEXT("*.*"))));
  782.  
  783.     BOOL bFileFound(TRUE);
  784. #ifdef WIN32
  785.     WIN32_FIND_DATA fileData;
  786.  
  787.     HANDLE hFindFile = FindFirstFile(filePath.GetPath(), &fileData);
  788.     // As long a something is found, but is not a good one, keep searching
  789.     // ... Ignore non-subdirectories and subdirectories starting with a full steop
  790.     if(hFindFile != INVALID_HANDLE_VALUE)
  791.         {
  792.         while(bFileFound)
  793.             {
  794.             if (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  795.                 {
  796.                 bFileFound = FindNextFile(hFindFile, &fileData);
  797.                 continue;
  798.                 }
  799.             VERIFY(filePath.SetFileName(fileData.cFileName));
  800.             // If the file is Read/only and it is allowed to remove it, try so
  801.             if (fileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
  802.                 {
  803.                 if (bAlsoRemoveReadOnly)
  804.                     {
  805.                     if (!SetFileAttributes(filePath.GetPath(), fileData.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY))
  806.                         {
  807.                         TRACE(TEXT("CDirSpec::RemoveAllFiles : Could not change the Read/Only attribute of file %s\n"), 
  808.                                     filePath.GetPath());
  809.                         ::FindClose(hFindFile);
  810.                         return FALSE;
  811.                         }
  812.                     }
  813.                 else
  814.                     {
  815.                     TRACE(TEXT("CDirSpec::RemoveAllFiles : Could not remove the file %s, because it is Read/Only\n"), 
  816.                                 filePath.GetPath());
  817.                     ::FindClose(hFindFile);
  818.                     return FALSE;
  819.                     }
  820.                 }
  821.             if (!DeleteFile(filePath.GetPath()))
  822.                 {
  823.                 TRACE(TEXT("CDirSpec::RemoveAllFiles : Could not remove the file %s\n"), filePath.GetPath());
  824.                 ::FindClose(hFindFile);
  825.                 return FALSE;
  826.                 }
  827.             bFileFound = FindNextFile(hFindFile, &fileData);
  828.             }  //while
  829.         
  830.         ::FindClose(hFindFile);
  831.         } // if(INVALID_HANDLE_VALUE)
  832. #else
  833.     _find_t fileInfo;
  834.  
  835.     VERIFY(filePath.SetPath(*this, CFileSpec(TEXT("*.*"))));
  836.     bFileFound = !_dos_findfirst(filePath.GetPath(), _A_ALL, &fileInfo);
  837.     while(bFileFound)
  838.         {
  839.         VERIFY(filePath.SetFileName(fileInfo.name));
  840.         // If the file is Read/only and it is allowed to remove it, try so
  841.         if (fileInfo.attrib & _A_RDONLY)
  842.             {
  843.             if (bAlsoRemoveReadOnly)
  844.                 {
  845.                 if (_dos_setfileattr(filePath.GetPath(), fileInfo.attrib & ~_A_RDONLY) != 0)
  846.                     {
  847.                     TRACE(TEXT("CDirSpec::RemoveAllFiles : Could not change the Read/Only attribute of file %s\n"), 
  848.                                 filePath.GetPath());
  849.                     return FALSE;
  850.                     }
  851.                 }
  852.             else
  853.                 {
  854.                 TRACE(TEXT("CDirSpec::RemoveAllFiles : Could not remove the file %s, because it is Read/Only\n"), 
  855.                             filePath.GetPath());
  856.                 return FALSE;
  857.                 }
  858.             }
  859.         if (remove(filePath.GetPath()) != 0)
  860.             {
  861.             TRACE(TEXT("CDirSpec::RemoveAllFiles : Could not remove the file %s\n"), filePath.GetPath());
  862.             return FALSE;
  863.             }
  864.  
  865.         bFileFound = !_dos_findnext(&fileInfo);
  866.         }
  867. #endif
  868.  
  869.     return TRUE;
  870.     } 
  871.     
  872.     
  873. // private:
  874.  
  875. // Message handlers ---------------------------------------------------------
  876.  
  877. // ==========================================================================
  878.